package com.polaris.live.widget

import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ObjectAnimator
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.animation.LinearInterpolator
import android.widget.FrameLayout
import com.blankj.utilcode.util.ColorUtils
import com.blankj.utilcode.util.ScreenUtils
import com.polaris.live.common.R
import com.polaris.live.common.ext.autoDp
import com.polaris.live.common.ext.setOnSingleClickListener
import com.polaris.live.common.manager.CoroutineScopeManager
import com.polaris.live.common.util.AppCodeUtils
import com.polaris.live.common.util.StructUtils
import com.polaris.live.databinding.LayoutBarrageViewBinding
import com.polaris.live.im.sfs.bean.live.AtUser
import com.polaris.live.im.sfs.bean.live.SendLiveMessage
import com.polaris.live.im.sfs.bean.live.ext.MessageUserExtBean
import com.polaris.live.im.sfs.bean.live.ext.UserBasicVo
import com.polaris.live.im.sfs.bean.live.payload.PublicScreenPayloadBean
import com.polaris.live.utils.RichCharmImgUtil
import com.polaris.live.widget.avatar.FrameImageUtils
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.util.UUID
import java.util.concurrent.ConcurrentLinkedQueue
import java.util.concurrent.LinkedBlockingDeque
import kotlin.random.Random

/**
 * BarragePlayView 弹幕播放view
 * @author Created by 天晴 on 2024/12/11 10:48
 * @since 1.0.0
 **/
class BarragePlayView(context: Context, attrs: AttributeSet?) : FrameLayout(context, attrs) {

    private val mSpeedRatio = 5f //速度比

    private val mScreenWidth by lazy {
        ScreenUtils.getScreenWidth()
    }
    private val mScreenHeight by lazy {
        ScreenUtils.getScreenHeight()
    }

    private val mViewHeight by lazy {
        80.autoDp
    }

    private val isAr by lazy {
        AppCodeUtils.isAR()
    }

    private val cacheViewList = ConcurrentLinkedQueue<LayoutBarrageViewBinding>() //緩存View
    private val waitList = LinkedBlockingDeque<BarragePlayBean>() //等待展示隊列

    //控件位置信息 translationX top height
    private val positionList = StructUtils.newSaleSet<PositionBean>() //等待展示隊列

    private var parentWidth: Int = 0   //当前控件宽
    private var parentHeight: Int = 0  //当前控件高

    private val NO_CHECK_TIME = 5000L

    private var callBack: ((user: UserBasicVo) -> Unit)? = null

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        val widthMode = MeasureSpec.getMode(widthMeasureSpec)
        val widthSize = MeasureSpec.getSize(widthMeasureSpec)
        val heightMode = MeasureSpec.getMode(heightMeasureSpec)
        val heightSize = MeasureSpec.getSize(heightMeasureSpec)
        parentWidth = mScreenWidth
        parentHeight = mScreenHeight
        when (widthMode) {
            MeasureSpec.EXACTLY -> parentWidth = widthSize
            MeasureSpec.AT_MOST -> parentWidth = parentWidth.coerceAtMost(widthSize)
            MeasureSpec.UNSPECIFIED -> parentWidth = mScreenWidth
        }
        when (heightMode) {
            MeasureSpec.EXACTLY -> parentHeight = heightSize
            MeasureSpec.AT_MOST -> parentHeight = parentHeight.coerceAtMost(heightSize)
            MeasureSpec.UNSPECIFIED -> parentHeight = mScreenHeight
        }
        setMeasuredDimension(parentWidth, parentHeight)
    }

    fun addReportCallBack(callBack: (user: UserBasicVo) -> Unit) {
        this.callBack = callBack
    }

    /**
     * 添加弹幕
     */
    fun addMessage(sendLiveMessage: SendLiveMessage) {
        addWaitQueue(sendLiveMessage)
    }

    /**
     * 实际添加view
     */
    private fun addBarrageView(
        sendLiveMessage: SendLiveMessage,
        viewTop: Int,
    ) {
        val ext = sendLiveMessage.ext as? MessageUserExtBean
        val payload = sendLiveMessage.payload as? PublicScreenPayloadBean
        ext?.user?.let { user ->
            val mBinding = getLayoutBarrageViewBinding()
            setDataView(mBinding, user, ext.atUsers, sendLiveMessage.content, payload?.translateContent)
            val viewMeasuredWidth = measureSpecView(mBinding.root).first
            val viewMeasuredHeight = measureSpecView(mBinding.root).second
            val lp = LayoutParams(viewMeasuredWidth, LayoutParams.WRAP_CONTENT)
            lp.topMargin = viewTop
            mBinding.root.layoutParams = lp
            val positionBean =
                PositionBean(
                    UUID.randomUUID().toString(),
                    parentWidth,
                    viewTop,
                    viewMeasuredWidth,
                    viewMeasuredHeight + 30
                ).also {
                    mBinding.root.tag = it
                    positionList.add(it)
                }
            addView(mBinding.root)
            startAnm(mBinding, viewMeasuredWidth, positionBean)
        }
    }

    /**
     * 測量寬
     */
    private fun measureSpecView(view: View): Pair<Int, Int> {
        val widthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
        val heightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
        view.measure(widthMeasureSpec, heightMeasureSpec)
        return Pair(view.measuredWidth, view.measuredHeight)
    }

    /**
     * 設置數據
     */
    private fun setDataView(
        mBinding: LayoutBarrageViewBinding,
        user: UserBasicVo,
        atUsers: List<AtUser>?,
        message: String,
        translateMessage: String?,
    ) {
        mBinding.apply {
            translateMessageTv.visibility = GONE
            lineView.visibility = GONE

            avFv.setFrameImage(FrameImageUtils.urlToFrameImageBean(user.avatarFrame))
            avatar.setImageUrl(user.avatar, user.userId)
            nameTv.text = user.nickname
            nameTv.setNicknameColor(user.nicknameColor, R.color.white)
            vipView.setVipLevel(user.vipLevel)
            levelView.setData(user.sex, user.richs, user.charms)
            var atStr = ""
            atUsers?.forEach {
                atStr += "@ ${it.nickname}"
            }
            messageTv.text = atStr + message
            if (message != translateMessage && !translateMessage.isNullOrEmpty()) {
                translateMessageTv.visibility = VISIBLE
                lineView.visibility = VISIBLE
                translateMessageTv.text = atStr + translateMessage
            }
            warnLl.setOnSingleClickListener {
                callBack?.invoke(user)
            }
            (RichCharmImgUtil.serColor2HexColor(user.nicknameColor)
                ?: ColorUtils.getColor(com.polaris.live.R.color.white)).let {
                messageTv.setTextColor(it)
                translateMessageTv.setTextColor(it)
            }
        }
    }

    private fun startAnm(mBinding: LayoutBarrageViewBinding, viewWidth: Int, positionBean: PositionBean) {
        val view = mBinding.root
        val time = (parentWidth + viewWidth) * mSpeedRatio

        val startIndex = if (isAr) -parentWidth.toFloat() else parentWidth.toFloat()
        val endIndex = if (isAr) viewWidth.toFloat() else -viewWidth.toFloat()

        val animatorCenterX =
            ObjectAnimator.ofFloat(view, "translationX", startIndex, endIndex)
        animatorCenterX.interpolator = LinearInterpolator()
        animatorCenterX.duration = time.toLong()
        // 添加更新监听
        animatorCenterX.addUpdateListener { animation ->
            val currentValue = animation.animatedValue as Float
            positionBean.translationX = currentValue.toInt()
        }
        animatorCenterX.addListener(object : AnimatorListenerAdapter() {
            override fun onAnimationEnd(animation: Animator) {
                view.post {
                    view.parent?.let {
                        if (cacheViewList.size < 20) {
                            cacheViewList.offer(mBinding)
                        }
                        positionList.remove(view.tag)
                        (it as ViewGroup).removeView(view)
                    }
                }

            }
        })
        animatorCenterX.start()
    }

    private fun getLayoutBarrageViewBinding(): LayoutBarrageViewBinding {
        stopCleanCacheJob()
        return cacheViewList.poll() ?: LayoutBarrageViewBinding.inflate(
            LayoutInflater.from(context),
            null,
            false
        )

    }

    override fun onDetachedFromWindow() {
        super.onDetachedFromWindow()
        cacheViewList.clear()
        waitList.clear()
        stopQueueJob()
        stopCleanCacheJob()
    }

    /**
     * 查找一个最大位置 直接插入
     * 是否有位置
     * 开始top
     * height
     */
    private fun checkMaxPosition(): Pair<Boolean, Int> {
        var isValid = false
        var top = 0

        if (childCount == 0 && parentHeight > mViewHeight) {
            return Pair(true, 0)
        }

        val intervals = positionList.filter {
            if (isAr) {
                it.translationX <= -parentWidth + it.width
            } else {
                it.translationX + it.width >= parentWidth
            }
        }.sortedBy { it.top }
        var previousEnd = 0
        var maxHeight = -1
        for (interval in intervals) {
            val h = interval.top - previousEnd
            if (h >= mViewHeight) {
                top = previousEnd
                isValid = true
                break
            }
            if (h > maxHeight) {
                maxHeight = h
                top = previousEnd
            }
            previousEnd = interval.top + interval.height
        }

        if (!isValid && parentHeight - previousEnd >= mViewHeight) {
            top = previousEnd
            isValid = true
        }
        if (isValid) {
            return Pair(true, top)
        }
        if (parentHeight - previousEnd > maxHeight) {
            top = parentHeight - mViewHeight
        }
        if (top == 0) {
            val a = Random.nextInt(0, parentHeight - mViewHeight)
            return Pair(false, a)
        }
        return Pair(false, top)
    }

    /**
     * 添加到等待队列
     */
    @Synchronized
    private fun addWaitQueue(sendLiveMessage: SendLiveMessage) {
        waitList.offer(BarragePlayBean(sendLiveMessage, System.currentTimeMillis()))
        if (queueJob == null || queueJob?.isActive != true) { // 检查队列为空或不在运行启动
            startAutoCleanup()
        }
    }

    private var queueJob: Job? = null //轮询等待队列
    val lock = Any()

    /**
     * 检查队列里面是否有超过3秒未展示的数据
     */
    private fun startAutoCleanup() {
        stopQueueJob()
        queueJob = CoroutineScopeManager.ioScope.launch {
            try {
                while (isActive) {
                    if (waitList.isEmpty()) {
                        stopQueueJob()
                        cleanCache()
                        break
                    }
                    while (isActive) {
                        val item = waitList.poll() ?: break
                        val (pd, viewTop) = checkMaxPosition()
                        if (pd) {
                            withContext(CoroutineScopeManager.mainDispatcher) {
                                addBarrageView(item.data, viewTop)
                            }
                        } else {
                            waitList.offerFirst(item)
                            break
                        }
                    }
                    delay(1000)
                }
            } catch (e: Exception) {
                stopQueueJob()
            }
        }
    }

    /**
     * 停止队列检查任务
     */
    private fun stopQueueJob() {
        queueJob?.cancel()
        queueJob = null
    }

    private var cleanCacheJob: Job? = null //轮询等待队列

    /**
     * 倒计时删除缓存view
     */
    private fun cleanCache() {
        stopCleanCacheJob()
        cleanCacheJob = CoroutineScopeManager.ioScope.launch {
            delay(60 * 1000)
            cacheViewList.clear()
        }
    }

    /**
     * 停止队列检查任务
     */
    private fun stopCleanCacheJob() {
        cleanCacheJob?.cancel()
        cleanCacheJob = null
    }
}

data class PositionBean(
    val id: String, // 唯一标识
    var translationX: Int,
    var top: Int,
    var width: Int,
    var height: Int,
) {

    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (other !is PositionBean) return false
        return id == other.id
    }

    override fun hashCode(): Int = id.hashCode()
}

data class BarragePlayBean(
    val data: SendLiveMessage,
    /**
     * 添加時間
     */
    val addTime: Long,
)